/* -*- mode: c++ -*-
** control.cpp
** 
** Made by Kjetil Svarstad
** 
*/

#include "control.h"

int Control::X[9] = {3,8,1,2,9,5,7,6,4};
// Functionality for the Control class

// Constructor
Control::Control (sc_module_name name) : sc_module (name)
{ // Constructor code
  // Create defult control packet
        dataPacket.size = 3;
	dataPacket.id = 10;
	dataPacket.flag = 0;
	dataPacket.pushed = 0;
	control_priority = 10;
	
	SC_HAS_PROCESS (Control);
	SC_THREAD(main);
	arrayPos = 0;
}

void Control::buttonPushed(int buttonNumber)
{ // TODO: FIX INTERFACING
  //cout << "buttonPushed()" << buttonAddress << endl; 
  int buttonAddress = buttonNumber*4; //converting from address to number
  //cout << "buttonNumber: " << buttonNumber << endl;
  if(buttonNumber == 0)
	{ // Start button was pushed. Lights off and randomize buttonsequence.
		switchLight(0);
		arrayPos = 0;
		// Shuffle the X array to generate a new sequence.
		int temp, rand1;
		for(int i = 0;i++; i <= 8)
		{
			rand1 = rand() % 9; // Random position in X
			// Switch elements in X[i] with element in random pos.
			// Elements are allowed to switch with themselves.
			temp = X[i];
			X[i] = X[rand1];
			X[rand1] = temp;
		}
	}
	else
	{
		if(arrayPos <= 8)
		{// Prevent out of bounds.
		 // All lights are on and only the startbutton should be acknowledged at
		 // this point.
			if(buttonNumber == X[arrayPos++])
			{ // Correct button pushed. Increment array pos and turn on light.
				switchLight(buttonAddress);
			}
			else
			{// Wrong button was pushed; turn off all lights, keep sequence.
				switchLight(0);
				arrayPos = 0;
			}
		}
	}
}

void Control::check(int address){
  wait (SC_ZERO_TIME);
  // reading active memory address
  status = busp -> burst_read(control_priority, &dataPacket.id, address+4,1,false);
  if (status == SIMPLE_BUS_ERROR) cout << "BUS_ERROR AT READ" << endl;
  status = busp -> burst_read(control_priority, &dataPacket.pushed, address+8,1,false);
  //cout << "pushed? " << dataPacket.pushed << endl;
  if (status == SIMPLE_BUS_ERROR) cout << "BUS_ERROR AT READ" << endl;
  else if (dataPacket.pushed != 0) buttonPushed(dataPacket.id);
}

void Control::switchLight(int address){
  wait(100, SC_US);
  int zero = 0;
  if (address == 0){
    for (int i=0; i <= 9; i++){//reset call¨
      status = busp -> burst_write(control_priority, &zero, i*4,1,false);
      if (status == SIMPLE_BUS_ERROR) cout << "BUS_ERROR AT READ" << endl;
      wait (100, SC_US);
    }
  }
  else{
    zero = 1;
    status = busp -> burst_write(control_priority, &zero, address,1,false);
    if (status == SIMPLE_BUS_ERROR) cout << "BUS_ERROR AT READ" << endl; 
  }
  //cout << "switchLightexit: " << endl;
}

void Control::main()
{
  while (true){
    wait (SC_ZERO_TIME);
    //cout << "flag value precheck: " << dataPacket.flag*4 << endl;
    status = busp -> burst_read(control_priority, &dataPacket.flag, 40, 1, false);
    if (status == SIMPLE_BUS_ERROR) cout << "BUS_ERROR AT READ" << endl;
    else if (dataPacket.flag != 0){
      //check button order
      dataPacket.flag &= 0xffff0000;
      dataPacket.flag = dataPacket.flag >> 16;
      //cout << "checking address: " << (dataPacket.flag)  << endl;
      check(dataPacket.flag); // remove redundant bits
      // reset flag
      dataPacket.flag = 0;
      status = busp -> burst_write(control_priority, &dataPacket.flag, 40, 1, false);
      if (status == SIMPLE_BUS_ERROR) cout << "BUS_ERROR AT READ" << endl;
    }
    wait (1, SC_MS);
  }
}
	
